import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:number_spark_flutter/routes/ns_app_pages.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:dio/dio.dart';
import 'package:get/get.dart' hide FormData, Response;
import 'dio_log/interceptor/dio_log_interceptor.dart';
import 'ns_network_config.dart';
import 'ns_network_utils.dart';
import 'ns_result_data.dart';
import 'dart:ui' as ui;

final _setCookieReg = RegExp('(?<=)(,)(?=[^;]+?=)');

class NSHttpManager {
  static Dio? _dio;

  factory NSHttpManager() => _sharedInstance();
  static NSHttpManager? _instance;

  NSHttpManager._() {
    if (null == _dio) {
      _dio = Dio(BaseOptions(connectTimeout: const Duration(milliseconds: 60000)));
      // _dio!.interceptors.add(RequestInterceptors());
      _dio!.interceptors.add(DioLogInterceptor());
      // final cookieJar = CookieJar();
      // _dio!.interceptors.add(CookieManager(cookieJar));
    }
  }

  static NSHttpManager _sharedInstance() {
    _instance ??= NSHttpManager._();
    return _instance!;
  }

  static int getNowTempStamp() {
    return int.parse((DateTime.now().millisecondsSinceEpoch / 1000).toStringAsFixed(0));
  }

  ///通用的GET请求
  Future<NSResponseData> get(api, {required Map<String, dynamic> params, withLoading = true, hideMsg = false}) async {
    _dio!.options.connectTimeout = const Duration(milliseconds: 60000);
    _dio!.options.contentType = "application/json";
    //公共参数
    NSNetWorkConfig config = NSNetWorkUtils.config;
    Map<String, dynamic> commonParams = {
      'kst': '1',
      'pkg': config.packageName,
      'sys_lan': ui.window.locale.languageCode,
      'lang': ui.window.locale.languageCode,
      'ver': config.appVersionCode,
      'device-id': config.deviceId,
      'platform': config.platform,
      'model': config.model,
    };
    _dio!.options.headers.addAll(commonParams);
    _dio!.options.headers['Authorization'] = 'Bearer${NSNetWorkUtils.getAccessToken()}';
    try {
      Response response = await _dio!.get(api, queryParameters: params);
      return httpSuccessHandle(response, hideMsg);
    } on DioError catch (e) {
      return httpErrorHandle(e, hideMsg: hideMsg);
    }
  }

  Future<NSResponseData> delete(api, {required Map<String, dynamic> params, withLoading = true, hideMsg = false}) async {
    _dio!.options.connectTimeout = const Duration(milliseconds: 60000);
    _dio!.options.contentType = "application/json";
    _dio!.options.headers['Authorization'] = 'Bearer${NSNetWorkUtils.getAccessToken()}';
    try {
      Response response = await _dio!.delete(api, queryParameters: params);
      return httpSuccessHandle(response, hideMsg);
    } on DioError catch (e) {
      return httpErrorHandle(e, hideMsg: hideMsg);
    }
  }

  ///通用的POST请求
  Future<NSResponseData> post(api, {required params, isJson = true, hideMsg = false, isNeedCommonParams = true}) async {
    _dio!.options.connectTimeout = const Duration(milliseconds: 60000);
    _dio!.options.sendTimeout = const Duration(milliseconds: 60000);
    _dio!.options.receiveTimeout = const Duration(milliseconds: 60000);
    _dio!.options.contentType = "application/json";
    _dio!.options.responseType = ResponseType.json;
    NSNetWorkConfig config = NSNetWorkUtils.config;
    //公共参数
    if (isNeedCommonParams) {
      Map<String, dynamic> commonParams = {
        'kst': '1',
        'pkg': config.packageName,
        'sys_lan': ui.window.locale.languageCode,
        'lang': ui.window.locale.languageCode,
        'ver': config.versionName,
        'device-id': config.deviceId,
        'platform': config.platform,
        'model': config.model,
      };
      _dio!.options.headers.addAll(commonParams);
    }
    _dio!.options.headers['Authorization'] = 'Bearer${NSNetWorkUtils.getAccessToken()}';
    // }
    try {
      Response<dynamic> response = await _dio!.post(api, data: isJson ? params : FormData.fromMap(params));
      return httpSuccessHandle(response, hideMsg);
    } on DioError catch (e) {
      return httpErrorHandle(e, hideMsg: hideMsg);
    }
  }

  ///下载文件到本地
  ///urlPath 文件Url
  ///savePath 本地保存位置
  ///downloadProgressCallBack 下载文件回调
  Future<Response> downloadFile(String urlPath, String savePath, {DownloadProgressCallBack? downloadProgressCallBack}) async {
    Dio dio = Dio();
    return await dio.download(urlPath, savePath, onReceiveProgress: downloadProgressCallBack);
  }
}

typedef DownloadProgressCallBack = Function(int count, int total);

///成功处理
Future<NSResponseData> httpSuccessHandle(Response response, bool hideMsg) async {
  NSResponseData responseData;
  if (response.data is String || response.data is Map) {
    String responseStr = "";

    if (response.data is Map) {
      responseStr = jsonEncode(response.data);
    } else {
      responseStr = response.data.toString();
    }
    Map<String, dynamic> mapResult = jsonDecode(responseStr);
    responseData = NSResponseData.fromJson(mapResult);
  } else {
    responseData = NSResponseData.fromJson(response.data);
  }
  if (!responseData.isSuccess()) {
    String errorMsg = responseData.msg ?? "";
    if (errorMsg.isNotEmpty && !hideMsg) {
      BotToast.showText(text: errorMsg);
    }
    if (responseData.code == '10010303') {
      NSNetWorkUtils.setAccessToken('');
      Get.offAllNamed(NSRoutes.login);
    }
  }
  return responseData;
}

///处理错误
Future<NSResponseData> httpErrorHandle(DioError e, {hideMsg = false}) async {
  String errorMsg = "";
  if (e.type == DioErrorType.connectionTimeout || e.type == DioErrorType.receiveTimeout) {
    errorMsg = NSNetWorkUtils.config?.requestTimeoutTip ?? '';
  } else {
    errorMsg = NSNetWorkUtils.config?.requestErrorTip ?? '';
  }
  if (!hideMsg && errorMsg.isNotEmpty) {
    BotToast.showText(text: errorMsg);
  }
  return NSResponseData(code: "-1", data: {}, msg: errorMsg);
}

String getCookies(List<Cookie> cookies) {
// Sort cookies by path (longer path first).
  cookies.sort((a, b) {
    if (a.path == null && b.path == null) {
      return 0;
    } else if (a.path == null) {
      return -1;
    } else if (b.path == null) {
      return 1;
    } else {
      return (b.path!.length).compareTo(a.path!.length);
    }
  });
  return cookies.map((cookie) => '${cookie.name}=${cookie.value}').join('; ');
}
